﻿#region License
/* Copyright (C) 2009 Tim Coulter
 * 
 * This file is part of ExtremeML.
 * 
 * ExtremeML is free software: you can redistribute
 * it and/or modify it under the terms of the GNU General Public
 * License, as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 * 
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
 * the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/.
*/
#endregion

using System;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using DocumentFormat.OpenXml.Packaging;
using ExtremeML.Core;

namespace ExtremeML.Sdk.Vml
{
	/// <summary>
	/// Stores the definition of a Vml drawing.
	/// </summary>
	public class VmlDrawing : IWrapper
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="VmlDrawing"/> class.
		/// </summary>
		/// <param name="elements">An array of <see cref="VmlElement"/> that represents child elements.</param>
		internal VmlDrawing(
			params VmlElement[] elements)
		{
			Document = new XDocument(GetDefaultElementContent(elements));
			CommentShapes = new CommentShapeCollection(this);
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="VmlDrawing"/> class.
		/// </summary>
		/// <param name="document">An <see cref="XDocument"/> from which to populate the new instance.</param>
		internal VmlDrawing(
			XDocument document)
		{
			if (document == null) throw new ArgumentNullException("document");

			Document = document;
			CommentShapes = new CommentShapeCollection(this);
		}

		/// <summary>
		/// Gets the contained <see cref="XDocument"/> instance.
		/// </summary>
		internal XDocument Document { get; private set; }

		/// <summary>
		/// Gets the set of shape elements that are used as cell comment shapes.
		/// </summary>
		internal CommentShapeCollection CommentShapes { get; private set; }

		/// <summary>
		/// Establishes relationships with other package content objects.
		/// </summary>
		public void Activate()
		{
            // This class requires no explicit activation.
        }

		/// <summary>
		/// Safely terminates relationships with other package content objects.
		/// </summary>
		public void Deactivate()
		{
			// This class requires no explicit deactivation.
		}

		/// <summary>
		/// Returns a value that indicates whether this instance wraps content that should be saved to the document.
		/// </summary>
		/// <returns><c>true</c> when the instance was constructed with a non-null member value or when
		/// the value of a scalar or wrapper property has been modified; otherwise, <c>false</c>.</returns>
		public bool IsPopulated()
		{
			return CommentShapes.Count() > 0;
		}

		/// <summary>
		/// Saves the content of this instance and its descendents to the passed <see cref="VmlDrawingPart"/>.
		/// </summary>
		/// <param name="part">A <see cref="VmlDrawingPart"/> to which element content should be saved.</param>
		internal void Save(
			VmlDrawingPart part)
		{
			if (part == null) throw new ArgumentNullException("part");

			var settings = new XmlWriterSettings
			{
				CloseOutput = true
			};

			using (var stream = part.GetStream(FileMode.Create))
			using (var writer = XmlWriter.Create(stream, settings))
			{
				Document.Save(writer);
			}
		}

		/// <summary>
		/// Ensures that the document contains a <see cref="CommentShapeType"/> element.
		/// </summary>
		internal void EnsureCommentShapeType()
		{
			var query = string.Format("./v:shapetype[@id='{0}']", CommentShapeType.ShapeTypeId);
			var element = Document.Root.XPathSelectElement(query, Utility.Manager);

			if (element == null)
			{
				Document.Root.Add(new CommentShapeType().Element);				
			}
		}

		/// <summary>
		/// Ensures that the document contains a <see cref="CommentShapeLayout"/> element.
		/// </summary>
		internal void EnsureCommentShapeLayout()
		{
			if (Document.Root.Element(Utility.O + "shapelayout") == null)
			{
				Document.Root.Add(new CommentShapeLayout().Element);
			}
		}

		/// <summary>
		/// Returns an <see cref="XElement"/> containing the default content for this class.
		/// </summary>
		private static XElement GetDefaultElementContent(
			params VmlElement[] elements)
		{
			return new XElement("xml",
				new XAttribute(XNamespace.Xmlns + "v", Utility.V),
				new XAttribute(XNamespace.Xmlns + "o", Utility.O),
				new XAttribute(XNamespace.Xmlns + "x", Utility.X),
				from element in elements select element.Element);
		}
	}
}